#!/usr/bin/env python
# -*- coding: utf8 -*-
# title       :
# description :
# author      :'ShenMeng'


from PySide import QtGui, QtCore
import os
import socket
import getpass
# import _winreg


from functools import partial
import subprocess

import yaml
import uuid
from . import resources_rc
from . import ui_style
from .verbatchmanager import BatchManager
from .task_thread import TaskThread
from .submit_button import SubmitBtn
from .local_task_page import LocalTaskPage
from .server_task_page import ServerTaskPage
from .info_page import InfoPage


class BatchManagerUi(QtGui.QWidget):
    
    def __init__(self, config=None, parent=None):
        super(BatchManagerUi, self).__init__(parent=parent)
        self.setStyleSheet(ui_style.STANDARD_STYLE)
        self._manager_data = []
        self._title = 'batch manager'
        self.setWindowTitle(self._title)
        self._config = config
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(':/icons/night.png'), QtGui.QIcon.Normal, QtGui.QIcon.Off)

        self.setWindowIcon(icon)
        if self._init_data():
            self._ui()

                
    def _ui(self):  
        #####################
        ###### set area #####
        #####################
        #--- root path layout ---#
        # create
        _root_label = QtGui.QLabel('Path : ')
        self.root_line = QtGui.QLineEdit()
        self.root_line.setMinimumHeight(22)
        self.root_btn = QtGui.QPushButton('...')
        self.root_btn.setMaximumSize(40, 22)
        self.root_btn.setMinimumSize(40, 22)
        # connect
        self.root_btn.clicked.connect(self.on_root_btn_clicked)
        # layout
        root_layout = QtGui.QHBoxLayout()
        root_layout.setSpacing(4)
        root_layout.setContentsMargins(4, 0, 0,0)
        root_layout.addWidget(_root_label)
        root_layout.addWidget(self.root_line)
        root_layout.addWidget(self.root_btn)
        
        #--- task type ---#
        # create
        self.task_type_frame = QtGui.QFrame()
        self.task_type_frame.setEnabled(0)
        self.task_type_frame_layout = QtGui.QVBoxLayout(self.task_type_frame)
        
        # create type from config
        self._box = {}
        grp_data = {}
        for name in self._data.keys():
            grp_index = self._data[name].get('group', 0)
            grp_data.setdefault(grp_index, []).append(name)
        grp_index_list = grp_data.keys()
        grp_index_list.sort()
        for grp_index in grp_index_list:
            grp_layout = QtGui.QHBoxLayout()
            grp_layout.setContentsMargins(4, 0, 0,0)
            grp_layout.setSpacing(10)
            for name in grp_data[grp_index]:
                subData = self._data[name].get('sub')
                if not subData:
                    box = QtGui.QCheckBox(name)
                    box_uuid = uuid.uuid4().hex
                    box.stateChanged.connect(partial(self.on_task_type_box_clicked, box_uuid))
                    self._box[box_uuid] = dict(box=box, type=str(name), sub='all')
                    grp_layout.addWidget(box)
                else:
                    type_label = QtGui.QLabel('{}:'.format(name.capitalize()))
                    grp_layout.addWidget(type_label)
                    ###
                    box = QtGui.QCheckBox('all')
                    box_uuid = uuid.uuid4().hex

                    box.stateChanged.connect(partial(self.on_task_type_box_clicked, box_uuid))
                    self._box[box_uuid] = dict(box=box, type=str(name), sub='all')

                    grp_layout.addWidget(box)
                    sub_keys = subData.keys()
                    sub_keys.sort()
                    for sub_type in sub_keys:
                        box = QtGui.QCheckBox(sub_type)
                        box_uuid = uuid.uuid4().hex
                        box.stateChanged.connect(partial(self.on_task_type_box_clicked, box_uuid))
                        self._box[box_uuid] = dict(box=box, type=str(name), sub=str(sub_type))
                        grp_layout.addWidget(box)
                
            grp_layout.addItem(QtGui.QSpacerItem(0,0,QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding))
            self.task_type_frame_layout.addLayout(grp_layout)
            #    
            
        #--- sel num and slider ---#
        # create
        self.sel_num_line = QtGui.QLineEdit()
        self.sel_num_line.setMaximumSize(35, 18)
        self.sel_num_slider = QtGui.QSlider()
        self.sel_num_slider.setOrientation(QtCore.Qt.Horizontal)
        self.sel_num_slider.setEnabled(0)
        # connect
        self.sel_num_slider.valueChanged.connect(self.on_sel_num_slider_value_changed)
        # layout
        task_select_layout = QtGui.QHBoxLayout()
        task_select_layout.addWidget(self.sel_num_line)
        task_select_layout.addWidget(self.sel_num_slider)
        task_select_layout.setContentsMargins(4, 0, 0,0)
        task_select_layout.setSpacing(0)
        task_select_layout.setStretch(1, 10)
        
        
        #--- file list ---#
        # create
        self.file_list_widget = QtGui.QListWidget()
        self.file_list_widget.setFocusPolicy(QtCore.Qt.NoFocus)
        self.file_list_widget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        # connect
        self.file_list_widget.itemSelectionChanged.connect(self.on_file_list_widget_selection_changed)
        
        
        #--- submit button ---#
        # create
        self.submit_btn = SubmitBtn('Submit')
        self.submit_btn.setEnabled(0)
        # connect
        self.submit_btn.clicked.connect(self.on_submit_btn_clicked)

        
        self.task_type_frame_layout.addLayout(task_select_layout)
        self.task_type_frame_layout.addWidget(self.file_list_widget)
        self.task_type_frame_layout.addWidget(self.submit_btn)
        self.task_type_frame_layout.setStretch(len(grp_index_list)+1,10)
        self.task_type_frame_layout.setContentsMargins(0,0,0,0)
        
        set_area_layout = QtGui.QVBoxLayout()#submit_page)
        set_area_layout.addLayout(root_layout)
        set_area_layout.addWidget(self.task_type_frame)
        set_area_layout.setStretch(1,10)
        set_area_layout.setContentsMargins(0,0,0,0)

        #####################
        ###### task area ####
        #####################
        #--- create pages ---#
        self.stacked_widget = QtGui.QStackedWidget()
        self.local_page = LocalTaskPage(self)
        self.server_page = ServerTaskPage(self)
        self.info_page = InfoPage()
        self.stacked_widget.addWidget(self.local_page)
        self.stacked_widget.addWidget(self.server_page)
        self.stacked_widget.addWidget(self.info_page)
        
        #--- checkout page ---#
        # create
        self.task_radio_btn_grp = QtGui.QButtonGroup()
        local_task_btn = QtGui.QCheckBox("local")
        local_task_btn.setChecked(1)
        server_task_btn = QtGui.QCheckBox("server")
        info_btn = QtGui.QCheckBox("info")
        self.task_radio_btn_grp.addButton(local_task_btn,0)
        self.task_radio_btn_grp.addButton(server_task_btn,1)
        self.task_radio_btn_grp.addButton(info_btn,2)
        self.server_refresh_btn = QtGui.QToolButton()
        self.server_refresh_btn.setIcon(QtGui.QIcon(":icons/refresh.png"))
        # connect
        self.task_radio_btn_grp.buttonClicked.connect(self.on_page_btn_clicked)
        self.server_refresh_btn.clicked.connect(self.on_server_refersh_btn_clicked)
        # layout
        task_btn_layout = QtGui.QHBoxLayout()
        task_btn_layout.addItem(QtGui.QSpacerItem(0,0, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding))
        task_btn_layout.addWidget(local_task_btn)
        task_btn_layout.addWidget(server_task_btn)
        task_btn_layout.addWidget(info_btn)
        task_btn_layout.addWidget(self.server_refresh_btn)
        task_btn_layout.setContentsMargins(4,4,4,4)
        task_btn_layout.setSpacing(10)
        
        
        #
        task_area_layout = QtGui.QVBoxLayout()
        task_area_layout.setContentsMargins(0,0,0,0)
        task_area_layout.addWidget(self.stacked_widget)
        task_area_layout.addLayout(task_btn_layout)
        task_area_layout.setStretch(0, 10)
        #
        
        # main frame
        main_frame = QtGui.QFrame()
        main_frame_layout = QtGui.QHBoxLayout(main_frame)
        main_frame_layout.addLayout(set_area_layout)
        main_frame_layout.addLayout(task_area_layout)
        main_frame_layout.setStretch(1,10)
        main_frame_layout.setContentsMargins(0,0,0,0)
        # >> main layout
        self.main_layout = QtGui.QVBoxLayout(self)
        self.main_layout.setSpacing(0)
        self.main_layout.setContentsMargins(0,0,0,0)
        self.main_layout.addWidget(main_frame)
        
        # connect
        self.TaskThread = TaskThread(item_model=self.local_page.view_model)
        # self.connect(self.TaskThread, QtCore.SIGNAL('updateinfo'), self.updateinfo)
        
        self._set_logo()
        
    def _set_logo(self):
        try:
            from framewidget import LogoFrame
            logo_frame = LogoFrame(name=self._title)
            logo_frame.set_bottom_border(1)
            self.main_layout.insertWidget(0, logo_frame)
        except:pass
        
    def _init_data(self):
        config_file = self.get_config_file()
        if config_file:
            try:
                with open(config_file) as f:
                    self._data = yaml.load(f)
            except:
                pass
            else:
                return True
        message_box = QtGui.QMessageBox().information(self, u'提示', u'配置文件错误！请联系TD解决！')
        
    def _refresh(self):
        for name in self._box:
            box = self._box[name]['box']
            box.setCheckState(QtCore.Qt.Unchecked) 
            
    def get_config_file(self):
        if not self._config:
            config_path = os.getenv("BATCH_MANAGER_CONFIG")
            if not config_path:
                return
            if os.path.isfile(config_path):
                return config_path
            return
            
        if os.path.isfile(self._config):
            return self._config
        else:
            config_path = os.getenv("BATCH_MANAGER_CONFIG")
            if config_path:
                if os.path.isfile(config_path):
                    config_file = config_path
                elif os.path.isdir(config_path):
                    config_file = os.path.join(config_path, self._config)
            else:
                config_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config', self._config)
            if os.path.isfile(config_file):
                return config_file.replace('\\', '/')
                
    def scan_maya_files(self, root_path):
        maya_file = []
        if os.path.isdir(root_path):
            maya_file = [f for f in os.listdir(root_path) if f.endswith('.mb')]
        return maya_file
        
    def on_sel_num_slider_value_changed(self, value):
        self.file_list_widget.selectionModel().clear()
        for i in range(value):
            item = self.file_list_widget.item(i)
            item.setSelected(1)
            
    def on_file_list_widget_selection_changed(self):
        sel_items = self.file_list_widget.selectedItems()
        self.sel_num_line.setText(str(len(sel_items)))
        self.submit_btn.updateCustomText(str(len(sel_items)))
        
    def on_page_btn_clicked(self, *args):
        index = self.task_radio_btn_grp.checkedId()
        self.stacked_widget.setCurrentIndex(index)
        
    def on_root_btn_clicked(self):
        his_path = self.root_line.text()
        # set default root path
        if not os.path.isdir(his_path):
            his_path = 'H:/project_baosuheti_171128/009_animation/temp'
            
        file_dialog = QtGui.QFileDialog(self, directory=his_path)
        root_path = file_dialog.getExistingDirectory()
        if root_path:
            root_path = root_path.replace('\\', '/')
            self.root_line.setText(str(root_path))
            # 1. clear set area ui data
            self.file_list_widget.clear()
            self._refresh()
            
            # 2. set server info
            self.update_server_info(root_path)
            # 3. continue task of last quit
            if self.scan_maya_files(root_path):
                if not self.TaskThread.status:
                    
                    self.TaskThread.start()
                self.task_type_frame.setEnabled(1)
                
                if root_path in self._manager_data:
                    return
                self._manager_data.append(root_path)
                for box_uuid, type_data in self._box.iteritems():
                    manager = BatchManager(type_data['type'], root_path, type_data['sub'])
                    self.init_local_page(manager, type_data)
                return
        else:
            if self.root_line.text() and os.path.isdir(self.root_line.text()):
                return
            self.task_type_frame.setEnabled(0)
        
    def on_task_type_box_clicked(self, name, *args):
        self.file_list_widget.clear()
        box = self._box[name]['box']
        if box.isChecked():
            for n in self._box:
                if n != name:
                    box = self._box[n]['box']
                    box.setCheckState(QtCore.Qt.Unchecked)
                    
            type_data = self.get_task_type()
            if type_data:
                root_path = self.root_line.text()
                self.manager = BatchManager(type_data['type'], root_path, type_data['sub'])
                if self.manager.isAssignDataLock:
                    # TODO
                    box.setCheckState(QtCore.Qt.Unchecked)
                    message_box = QtGui.QMessageBox().information(self, u'提示', u'其他用户(ID:%s)正在提交中，数据被锁定，请稍后再试！' % self.manager.assignUser)
                else:
                    self.add_file_list_widget_item()
            else:
                self.manager = None
                self.submit_btn.setEnabled(0)
                self.sel_num_line.setEnabled(0)
                self.sel_num_slider.setEnabled(0)
            self.update_info()
            
    def on_submit_btn_clicked(self):
        items = self.file_list_widget.selectedItems()
        task_list = []
        if not items:
            return
        for item in items:
            task_list.append(item.text()) 
        if self.manager.isAssignDataLock:
            message_box = QtGui.QMessageBox().information(self, u'提示', u'其他用户(ID:%s)正在提交中，数据被锁定，请稍后再试！' % self.manager.assignUser)
            return
        self.manager.setAssignDataLock(1)
        assign_data = self.manager.assignData
        if assign_data:
            result_data = [f for f in task_list if f not in assign_data]
        else:
            result_data = task_list
        if result_data:
            #
            if self.manager.taskAssignData:
            
                result = {key:dict(status='Waiting', image=":icons/clock.png", user=self.manager.id) for key in result_data if key not in self.manager.taskAssignData }
            else:
                result = {key:dict(status='Waiting', image=":icons/clock.png", user=self.manager.id) for key in result_data}
            self.local_page.add_items(result, self.get_task_type(), manager=self.manager)
            # self.submit_task(self.get_batch_type(), result)
            
            data = {task:{"user":self.manager.id} for task in result_data}
            self.manager.updateAssignData(data)
            self.manager.updateTaskAssignData(result_data)
        self.manager.setAssignDataLock(0)
        self._refresh()
            
    def get_task_type(self):
        for name in self._box:
            box = self._box[name]['box']
            if box.isChecked():
                return dict(type=str(self._box[name]['type']), sub=str(self._box[name]['sub']))
                
    def get_cmd(self, manager, type_data, task_name):
        data = self._data[type_data['type']]
        engine = data['engine']
        if type_data['sub'] != 'all':
            script = data['sub'][type_data['sub']]['script']
        else:
            script = data['script']
        cmd_format = '{engine} -file "{file}" -script "{script}"'

        hooks_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'hooks', script).replace('\\', '/')
        # hooks_path = 'D:/apps/local/batchmanager/src/batchmanager/hooks/%s' % script
        file_path = os.path.join(manager.rootPath, task_name).replace('\\', '/')
        return cmd_format.format(engine=engine, file=file_path, script=hooks_path)

   
    def add_file_list_widget_item(self):
        self.file_list_widget.clear()
        root_path = self.root_line.text()
        if not os.path.isdir(root_path):
            return
        maya_file = self.scan_maya_files(root_path)
        if maya_file:
            if self.manager:
                assign_data = self.manager.assignData
                if assign_data:
                    result_data = [f for f in maya_file if f not in assign_data]
                else:
                    result_data = maya_file
                if result_data:
                    result_data.sort()
                    self.file_list_widget.addItems(result_data)
                    self.sel_num_slider.setMinimum(0)
                    self.sel_num_slider.setMaximum(len(result_data))
                    self.sel_num_slider.setEnabled(1)
                    self.submit_btn.setEnabled(1)
                    return
        self.sel_num_slider.setEnabled(0)
        self.submit_btn.setEnabled(0)
        
    def init_local_page(self, manager, type_data):
        """
        initial the local page task item
        """
        taskErrorData = manager.taskErrorData
        taskOkData = manager.taskOkData
        taskAssignData = manager.taskAssignData
        result = {}
        data = []
        if taskErrorData:
            for _error in taskErrorData.keys():
                result[_error] = dict(status='Ok', image=":icons/failure.png", user=manager.id)
            data.extend(taskErrorData.keys())
        if taskOkData:
            for _ok in taskOkData.keys():
                result[_ok] = dict(status='Ok', image=":icons/success.png", user=manager.id)
            data.extend(taskOkData.keys())
        if taskAssignData:
            result_data = [f for f in taskAssignData if f not in data]
            if result_data:
                for _assign in result_data:
                    result[_assign] = dict(status='Waiting', image=":icons/clock.png", user=manager.id)
        if result:
            self.local_page.add_items(result, type_data, manager=manager)
            
    def on_server_refersh_btn_clicked(self):
        root_path = self.root_line.text()
        if not os.path.isdir(root_path):
            return
        if root_path:
            root_path = root_path.replace('\\', '/')
            self.update_server_info(root_path)
            
        self.update_info()
        
    def update_server_info(self, root_path):
        """
        update server page task item
        update when root path changed 
        """
        self.server_page.initial_data()
        for box_uuid, type_data in self._box.iteritems():
            temp_manager = BatchManager(type_data['type'], root_path, type_data['sub'])
            errorData = temp_manager.errorData
            okData = temp_manager.okData
            assignData = temp_manager.assignData
            data = {}
            result = {}
            if errorData:
                for _error in errorData.keys():
                    result[_error] = dict(status='Ok', image=":icons/failure.png", user=errorData[_error]["user"])
                data.update(errorData)
            if okData:
                for _ok in okData.keys():
                    result[_ok] = dict(status='Ok', image=":icons/success.png", user=okData[_ok]["user"])
                data.update(okData)
            if assignData:
                assign_file = list(set(assignData))
                if data:
                    result_data = {f:assignData[f] for f in assign_file if f not in data}
                else:
                    result_data = assignData
                if result_data:
                    for _assign in result_data:
                        result[_assign] = dict(status='Waiting', image=":icons/clock.png", user=result_data[_assign]["user"])
            if result:
                self.server_page.add_items(result, type_data)
                
    def update_info(self):
        """
        update info page : show the error info
        update when root path and task type changed
        """
        root_path = self.root_line.text()
        if not root_path:
            self.info_page.update_info( error=1)
            return
        if not os.path.isdir(root_path):
            self.info_page.update_info( error=1)
            return
        type_data = self.get_task_type()
        if not type_data:
            self.info_page.update_info( error=1)
            return 
        
        temp_manager = BatchManager(type_data['type'], root_path, type_data['sub'])
        errorData = temp_manager.errorData
        if not errorData:
            self.info_page.update_info(dict(error=errorData, type_data=type_data))
            return
        self.info_page.update_info(dict(error=errorData, type_data=type_data))

if __name__ == "__main__":
    app = QtGui.QApplication([])
    bmui = BatchManagerUi()
    bmui.show()
    app.exec_()
        